﻿Imports System.Activities
Imports System.Drawing
Imports System.ComponentModel
Imports System.Activities.Core.Presentation
Imports System.Activities.Presentation.Metadata

Public Class ZipCompressActivity
    Inherits AsyncCodeActivity
    Implements IRegisterMetadata

    ''' <summary>空 Zip 書庫のバイナリ</summary>
    Private EMPTYZIP_ARRAY As Byte() = {&H50, &H4B, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

#Region "プロパティ"
    <RequiredArgument()>
    Public Property ArchiveFileName As InArgument(Of String)

    <RequiredArgument()>
    Public Property TargetFileName As InArgument(Of String)

    Public Property Results As OutArgument(Of Boolean)
#End Region

    Private Delegate Function asyncCompress(ByVal archive As String, ByVal target As String) As Boolean

    Public Sub New()
        Me.DisplayName = GetResourceStrings("ActZCDisplayName", "Zip ファイル圧縮")
    End Sub

#Region "メソッド"
    Protected Overrides Function BeginExecute(context As System.Activities.AsyncCodeActivityContext, callback As System.AsyncCallback, state As Object) As System.IAsyncResult

        Dim archive = context.GetValue(Me.ArchiveFileName)
        Dim target = context.GetValue(Me.TargetFileName)
        archive = IO.Path.GetFullPath(archive)
        target = IO.Path.GetFullPath(target)

        Dim asyncComp = New asyncCompress(AddressOf CompressFile)
        context.UserState = asyncComp

        Return asyncComp.BeginInvoke(archive, target, callback, state)
    End Function

    Protected Overrides Sub EndExecute(context As System.Activities.AsyncCodeActivityContext, result As System.IAsyncResult)
        Dim asyncExecute = TryCast(context.UserState, asyncCompress)
        Dim compResult = asyncExecute.EndInvoke(result)

        context.SetValue(Me.Results, compResult)
    End Sub

    Private Function CompressFile(ByVal archive As String, ByVal target As String) As Boolean

        Dim result As Boolean = False

        If Not IO.File.Exists(archive) Then Me.CreateEmptyZip(archive)

        Dim shl As Object = Nothing
        Dim zipFolder As Object = Nothing
        Dim zipFolderFilesCount As Object = Nothing
        Dim targetItem As Object = Nothing
        Try
            shl = CreateObject("Shell.Application")
            zipFolder = shl.NameSpace(IO.Path.GetFullPath(archive))
            zipFolderFilesCount = zipFolder.Items().Count
            targetItem = shl.NameSpace(IO.Path.GetFullPath(target & "\..")).ParseName(IO.Path.GetFileName(target))

            zipFolder.CopyHere(targetItem)
            Do Until zipFolder.Items().Count > zipFolderFilesCount
                System.Threading.Thread.Sleep(500)
            Loop
            result = True
        Catch ex As Exception
        Finally
            targetItem = Nothing
            zipFolderFilesCount = Nothing
            zipFolder = Nothing
            shl = Nothing
        End Try

        Return result
    End Function

    ''' <summary>Zip 空書庫の作成</summary>
    Private Sub CreateEmptyZip(ByVal archive As String)
        Using fs As New IO.FileStream(archive, IO.FileMode.Create)
            fs.Write(EMPTYZIP_ARRAY, 0, EMPTYZIP_ARRAY.Length)
        End Using
    End Sub
#End Region

#Region "メタデータ"

    Public Sub Register() Implements System.Activities.Presentation.Metadata.IRegisterMetadata.Register
        Dim metadata As New DesignerMetadata
        metadata.Register()

        Dim builder As New AttributeTableBuilder
        builder.AddCustomAttributes(GetType(ZipCompressActivity),
                            New DesignerAttribute(GetType(ZipCompressActivityDesigner)),
                            New ToolboxBitmapAttribute("Images/Activity/zippedfile.png")
                            )
        builder.AddCustomAttributes(GetType(ZipCompressActivity), "ArchiveFileName",
            New CategoryAttribute(GetResourceStrings("ACtZCPropertyCategory", "処理の設定")),
            New DisplayNameAttribute(GetResourceStrings("ACtZCArchiveFileNameProperty", "圧縮ファイル名")),
            New DescriptionAttribute(GetResourceStrings("ACtZCArchiveFileNameDescription", "出力する圧縮ファイル名を設定します。")))
        builder.AddCustomAttributes(GetType(ZipCompressActivity), "TargetFileName",
                    New CategoryAttribute(GetResourceStrings("ACtZCPropertyCategory", "処理の設定")),
                    New DisplayNameAttribute(GetResourceStrings("ACtZCTargetFileNameProperty", "圧縮するファイル")),
                    New DescriptionAttribute(GetResourceStrings("ACtZCTargetFileNameDescription", "圧縮するファイル名を設定します。")))
        builder.AddCustomAttributes(GetType(ZipCompressActivity), "Results",
                    New CategoryAttribute(GetResourceStrings("ACtZCPropertyCategory", "処理の設定")),
                    New DisplayNameAttribute(GetResourceStrings("ACtZCResultsProperty", "結果を受取る変数")),
                    New DescriptionAttribute(GetResourceStrings("ACtZCResultsDescription", "圧縮が正しく行えたか結果を返却します。")))

        MetadataStore.AddAttributeTable(builder.CreateTable)
    End Sub

#End Region

#Region "その他"

    ''' <summary>リソースより文字列の取得</summary>
    Private Shared Function GetResourceStrings(ByVal resourceName As String, ByVal defaultStrings As String)
        Dim locMes = CStr(Application.Current.TryFindResource(resourceName))
        If (locMes Is Nothing) OrElse (locMes.Trim = "") Then locMes = defaultStrings
        Return locMes
    End Function

#End Region

End Class